package com.yzy.fly.config;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationAdvisor;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDatasourceAopProperties;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.yzy.fly.boot.tableSharding.FlyTableShardConfigHandler;
import com.yzy.fly.config.properties.FlyProperties;
import com.yzy.fly.function.httpClient.FlyHttpClientConfig;
import com.yzy.fly.function.httpClient.FlyHttpClientConfigPool;
import com.yzy.fly.function.httpClient.FlyHttpClientDynamicTableNameInnerInterceptor;
import com.yzy.fly.function.httpClient.LogTableNameHandler;
import org.springframework.aop.Advisor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.TransactionAttributeSource;

import java.util.Map;

//@EnableConfigurationProperties({DynamicDataSourceProperties.class})
@EnableTransactionManagement
@Configuration
//@MapperScan(annotationClass = Mapper.class)//basePackages = {},
//@MapperScan({"com.yzy.fly.mapper.**","com.yzy.fly.api.*.mapper","com.yzy.fly.api.**.mapper","com.yzy.fly.api.***.mapper","com.yzy.fly.ide.mapper.**","com.yzy.fly.rbac.mapper.**"})
public class MybatisConfigurationTemp {

    private final DynamicDataSourceProperties properties;
    private final FlyProperties flyProperties;

    public MybatisConfigurationTemp(DynamicDataSourceProperties properties, FlyProperties flyProperties) {
        this.properties = properties;
        this.flyProperties = flyProperties;
    }

    /*
     * 分页插件，自动识别数据库类型
     * 多租户，请参考官网【插件扩展】
     */
//    @Bean
//    public PaginationInnerInterceptor paginationInnerInterceptor() {
//        return new PaginationInnerInterceptor();
//    }

//    @Bean
//    public GlobalConfig globalConfig() {
//        GlobalConfig globalConfig = new GlobalConfig();
//        globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());
//        return globalConfig;
//    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
//        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
//            // 获取参数方法
//            Map<String, Object> paramMap = RequestDataHelper.getRequestData();
////            paramMap.forEach((k, v) -> System.err.println(k + "----" + v));
////            // 自定义表名规则，或者从配置文件、request上下文中读取
////            // 假设这里的“用户表”根据年份来进行分表操作
////            if (tableName.equals("sys_user")) {
////                Date date = new Date();
////                String year = String.format("%tY", date);
////                // 返回最后需要操作的表名：sys_user_2019
////                return "sys_user_" + year;
////            }
//            return tableName;
//        });
//        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        // 3.4.3.2 作废该方式
        // dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);

        FlyHttpClientDynamicTableNameInnerInterceptor flyHttpClientDynamicTableNameInnerInterceptor = new FlyHttpClientDynamicTableNameInnerInterceptor();
        Map<String, FlyHttpClientConfig> config = FlyHttpClientConfigPool.getInstance().pool();
        LogTableNameHandler logTableNameHandler = new LogTableNameHandler(config);
        flyHttpClientDynamicTableNameInnerInterceptor.setTableNameHandler(logTableNameHandler);
        interceptor.addInnerInterceptor(flyHttpClientDynamicTableNameInnerInterceptor);
//        interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor(new ApiTraceTableNameHandler()));
        interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor(new FlyTableShardConfigHandler()));
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //DbType.H2
        return interceptor;
    }

    /*
     * oracle数据库配置JdbcTypeForNull
     * 参考：https://gitee.com/baomidou/mybatisplus-boot-starter/issues/IHS8X
     不需要这样配置了，参考 yml:
     mybatis-plus:
       confuguration
         dbc-type-for-null: 'null'
    @Bean
    public ConfigurationCustomizer configurationCustomizer(){
        return new MybatisPlusCustomizers();
    }

    class MybatisPlusCustomizers implements ConfigurationCustomizer {

        @Override
        public void customize(org.apache.ibatis.session.Configuration configuration) {
            configuration.setJdbcTypeForNull(JdbcType.NULL);
        }
    }
    */
    @Bean
    public ExpandSqlInjector expandSqlInjector() {
        return new ExpandSqlInjector();
    }

    @Bean
    public FlyMybatisAnnotationHandler flyMybatisAnnotationHandler() {
        return new FlyMybatisAnnotationHandler();
    }


    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean
    @ConditionalOnProperty(prefix = "fly." + DynamicDataSourceProperties.PREFIX + ".aop", name = "enabled", havingValue = "true", matchIfMissing = true)
    public Advisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {
        DynamicDatasourceAopProperties aopProperties = properties.getAop();
        FlyDynamicDataSourceAnnotationInterceptor interceptor = new FlyDynamicDataSourceAnnotationInterceptor(aopProperties.getAllowedPublicOnly(), dsProcessor,this.flyProperties);
        DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor, DS.class);
        advisor.setOrder(aopProperties.getOrder());
        return advisor;
    }

    @Bean
    @ConditionalOnProperty(prefix = "fly.configuration.transaction", name = "enable", havingValue = "true", matchIfMissing = true)
    public FlySpringTransactionAnnotationParser flySpringTransactionAnnotationParser() {
        return new FlySpringTransactionAnnotationParser(flyProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = "fly.configuration.transaction", name = "enable", havingValue = "true", matchIfMissing = true)
    public TransactionAttributeSource transactionAttributeSource(FlySpringTransactionAnnotationParser flySpringTransactionAnnotationParser) {
        return new AnnotationTransactionAttributeSource(flySpringTransactionAnnotationParser);
    }

}

